
import {createElement, setElementText, insert, patchProps, unmount} from './browserRendererOptions.js'
import {getSequence} from './getSequence.js'
export function createRenderer(options) {
  const {debuggerMountComponent, debuggerPatchComponent} = options

  function render (vnode, container) {
    if(vnode) {
      patch(container._vnode, vnode, container)
    } else {
      if(container._vnode) {
        unmount(container)
      }
    }
    container._vnode = vnode
  }

  function patch(n1, n2, container, anchor) {
    if(n1 && n1.type !== n2.type) {
      unmount(n1)
      n1 = null
    }
    const {type} = n2
    if(typeof type === 'string') { //dom
      if(!n1) {
        mountElement(n2, container, anchor)
      } else {
        patchElement(n1, n2)
      }
    } else if(typeof type === 'object')  { //component
      if(!n1) {
        //mountComponent(n2, container, anchor)
         debuggerMountComponent(patch)(n2, container, anchor)
      } else {
        console.log('patchComponent')
        debuggerPatchComponent()(n1, n2)
      }
    }
  }

  function mountElement(vnode, container, anchor) {
    const {type, children, props} = vnode
    const el = vnode.el = createElement(type)
    if(typeof children === 'string') {
      setElementText(el, children)
    } else if(Array.isArray(children)) {
      children.forEach(child=> patch(null, child, el, anchor))
    }
    if(props) {
      for(const key in props) {
        patchProps(el, key, null, props[key])
      }
    }
    insert(el, container, anchor)
  }

  function patchElement(n1, n2) {
    const el = n2.el = n1.el
    const oldProps = n1.props || {}
    const newProps = n2.props || {}
     //1.更新属性
    for(const key in oldProps) {
      if(!(key in newProps)) {
        patchProps(el, key, oldProps[key], null)
      }
    }
    for(const key in newProps) {
      if(newProps[key] !== oldProps[key]) {
        patchProps(el, key, oldProps[key], newProps[key])
      }
    }
    //2.更新子节点
    patchChildren(n1, n2, el)
  }

  function patchChildren(n1, n2,container) {
    const {children: newChildren} = n2
    const {children: oldChildren} = n1
    if(typeof newChildren === 'string') {
      if(Array.isArray(oldChildren)) {
        oldChildren.forEach(c=> unmount(c))
      }
      setElementText(container, newChildren)
    } else if(Array.isArray(newChildren)) {
      if(Array.isArray(oldChildren)) {
        patchKeyChildren(n1, n2,container)
      } else {
        setElementText(container, '')
        newChildren.forEach(c=> mountElement(c, container))
      }
    } else {
      if(Array.isArray(oldChildren)) {
        oldChildren.forEach(c=> unmount(c))
      } else if(typeof oldChildren === 'string'){
        setElementText(container, '')
      }
    } 
  }
  //快速diff
  function patchKeyChildren(n1, n2, container) {
    const newChildren = n2.children
    const oldChildren = n1.children
    //处理相同的前置节点
    //索引j指向新旧俩组节点的开头
    let j = 0
    let oldVnode = oldChildren[j]
    let newVnode = newChildren[j]
    //while 循环向右遍历，直到遇到拥有不同的 key 值的节点为止
    while(oldVnode.key === newVnode.key) {
      patch(oldVnode, newVnode, container)
      j++
      oldVnode = oldChildren[j]
      newVnode = newChildren[j]
    }
    //更新相同的后置节点
    //索引 oldEnd 指向旧的一组节点的最后一个节点
    //索引 newEnd 指向新的一组节点的最后一个节点
    let oldEnd = oldChildren.length - 1
    let newEnd = newChildren.length - 1
    oldVnode = oldChildren[oldEnd]
    newVnode = newChildren[newEnd]
    //while 循环从后向前遍历，直到遇到拥有不同的 key 值的节点 为止
    while(oldVnode.key === newVnode.key) {
      patch(oldVnode, newVnode, container)
      oldEnd --
      newEnd --
      oldVnode = oldChildren[oldEnd]
      newVnode = newChildren[newEnd]
    }
    debugger
    //预处理完毕后，如果满足如下条件，则说明 j --> newEnd 之间的节点作为新的节点插入
    if(j > oldEnd && j <= newEnd) {
      const anchorIndex = newEnd + 1
      //锚点元素
      const anchor = anchorIndex < newChildren.length ? newChildren[anchorIndex].el : null
      while(j <= newEnd) {
        patch(null, newChildren[j++], container, anchor)
      }
    }else if(j > newEnd && j <= oldEnd) {
      // j -> oldEnd 之间的节点应该被卸载
      while(j <= oldEnd) {
        unmount(oldChildren[j++])
      }
    } else {
      const count = newEnd - j + 1
      const source = new Array(count)
      source.fill(-1)
      const oldStart = j
      const newStart = j
      const keyIndex = {}
      //新增两个变量，moved 和 pos
      let moved = false
      let pos = 0
      //新增patched变量，代表更新过的节点数量
      let patched = 0
      for(let  i = newStart; i <= newEnd; i++) {
        const newVnode = newChildren[i]
        keyIndex[newVnode.key] = i
      }
      debugger
      for(let i = oldStart; i <= oldEnd; i++) {
        const oldVnode = oldChildren[i]
        if(patched < count) {
          const k = keyIndex[oldVnode.key]
          if(typeof k !== 'undefined') {
            patch(oldVnode, newChildren[k], container)
            //每更新一个节点，都将patched 变量 +1
            patched ++
            source[k - newStart] = i
            if(k < pos) {
              moved = true
            } else {
              pos = k
            }
          } else {
            //如果更新节点数量大于需要更新的节点数量，则卸载多余节点
            unmount(oldVnode)
          }
        } else {
          unmount(oldVnode)
        }
      }
      console.log(moved,'moved')
      if(moved) {
        debugger
        const seq = getSequence(source) // [0,1]
        //s 指向最长递增子序列的最后一个元素
        let s = seq.length - 1
        //i 指向新的一组子节点的最后一个元素
        let i = count - 1
        for(i; i >= 0; i--) {
          debugger
          if(source[i] === -1) {
            const pos = i + newStart
            const newVnode = newChildren[pos]
            const nextPos = pos + 1
            const anchor = nextPos < newChildren.length ? newChildren[nextPos].el : null
            patch(null, newVnode, container, anchor)
          } else if(i !== seq[s]) {
            const pos = i + newStart
            const newVnode = newChildren[pos]
            const nextPos = pos + 1
            const anchor = nextPos < newChildren.length ? newChildren[nextPos].el : null
            insert(newVnode.el, container, anchor)
          } else {
            // 当 i === seq[s]时，说明该位置的节点不需要移动
            s--
          }
        }
      }      
    }
  }

  function mountComponent(vnode, container, anchor) {}

  function patchComponent(n1, n2) {}

  return render
}


